#include "platestack.h"
#include <QTimer>
#include "componentmanager.h"
#include "component_log.h"
#include "platestack_data.h"
#include "stackplate/plate_data.h"
#include "stackplate/stackplatemanager.h"
#include "systemconfiguration.h"
#include "wcs/WCSSend.h"

PlateStack::PlateStack(QObject* parent)
	: ComponentBase(parent)
{
	m_name = u8"托盘垛数据管理器";
	m_errmsg = "";
	m_type = Component::component_systemInfo;
	m_time = new QTimer(this);
	m_time->setInterval(1000);
	connect(m_time, &QTimer::timeout, this, &PlateStack::OnTimeToExcute);
}

PlateStack::~PlateStack()
{}

bool PlateStack::GetGrabPosition(Position& pos)
{
	if (m_height.times > 3) {	// 连续3次计算出的高度一致后再输出坐标
		pos = m_info.base;
		pos.z += (m_height.num - 1) * m_info.plateH;
		log_trace("plate stack pos =({},{}, {}), {}", pos.x, pos.y, pos.z, m_height.height);
		return true;
	}

	return false;
}

PlateStackState PlateStack::GetPlateStackState()
{
	PlateStackState stat = {};
	stat.apply = m_apply;
	stat.num = m_height.num;
	return stat;
}
#define PLATE_APPLY ("/plate/apply")
structJ(PlateApply,
	mapping(QString, taskId);
mapping(QString, robNo);;
mapping(int, num);
mapping(QString, placeNo);
prop(&taskId, &robNo, &num, &placeNo);
);

structJ(ApplyAns,
	mapping(int, code);
mapping(QString, msg);
prop(&code, &msg);
)

QString PlateStack::ManualSendPlateApply()
{
	if (m_height.num == 0 && m_height.times > 3) {
		log_trace("Manual send plate num = 0, need send apply");
		PlateApply data = {};
		data.taskId = m_info.id;
		data.robNo = m_info.rob;
		data.num = 10;
		data.placeNo = m_info.id;
		QByteArray ans;
		ApplyAns ansData = {};
		if (m_wcs->SendToWCS(PLATE_APPLY, data.toByteArray(), ans)) {
			log_trace("send apply successed");
			ansData.fromJson(ans);
			if (ansData.code() < 0) {
				SetWarningmsg("托盘垛申请失败：" + ansData.msg());
				log_error("send to wcs apply msg failed, err = {}", ansData.msg());
				return "发送失败：" + ansData.msg();
			} else {
				return "发送成功，wcs同意请求";
			}
		} else {
			SetWarningmsg("向WCS申请托盘垛发送失败：" + ans);
			log_error("send to wcs apply msg failed, err = {}", ans);
			return "发送失败：" + ans;
		}
	} else {
		return "当前的托盘数量不为0，无法发送申请";
	}
}

// 组件初始化处理函数
int PlateStack::ComponentInit()
{
	auto cfg = syscfg->GetPlateStackCfg();
	if (!cfg.valid) {
		return COMMON_ERROR;
	}
	m_info.id = cfg.id;
	m_info.base = cfg.base;
	m_info.maxdi = cfg.maxDi;
	m_info.mindi = cfg.minDi;
	m_info.rob = cfg.rob;
	m_info.plateH = cfg.plateH;

	auto plateM = dynamic_cast<StackPlateManager*>(component->GetComponent(Component::component_stackPlate));
	if (plateM == nullptr) {
		SetErrmsg("未获取到码垛托盘管理组件，组件初始化失败");
		return COMMON_ERROR;
	}
	auto plates = plateM->GetPlateList();
	if (plates.isEmpty()) {
		SetWarningmsg("码垛托盘数量为空，无需创建托盘垛组件");
		return COMMON_ERROR;
	}
	for (auto& iter : plates) {
		PlateState state = {};
		state.plate = false;
		state.send = false;
		m_plates.emplace(iter, state);
	}

	auto rob = component->GetComponent(Component::component_robot);
	if (rob == nullptr) {
		SetErrmsg("机械手组件加载失败", false);
		return SERIOUS_ERROR;
	}
	rob->RegisterSubscriberFunction((int)RobotMsgType::robot_msg_DI, [&](const QByteArray& data) {
		return this->RobotSetDIInfo(data);
		});
	auto wcsr = (component->GetComponent(Component::component_wcsrec));
	if (wcsr == nullptr) {
		SetErrmsg("WCS 消息发送组件加载失败", false);
		return SERIOUS_ERROR;
	}

	wcsr->RegisterSubscriberFunction((int)WCSMsgType::wcs_msg_plate_arrive, [&](const QByteArray& data) {
		return this->WCSSendArrive(data);
		});

	m_wcs = dynamic_cast<WCSSend*>(component->GetComponent(Component::component_wcsSend));
	if (m_wcs == nullptr) {
		SetErrmsg("WCS 消息发送组件加载失败", false);
		return SERIOUS_ERROR;
	}
	m_time->start();
	return 0;
}
/*自检接口*/
bool PlateStack::ComponentCheckSelfState()
{
	return true;
}
/*复位接口*/
bool PlateStack::ComponentSelfReset()
{
	m_height.num = -1;
	m_height.height = 0;
	m_height.times = 0;
	m_di.clear();

	return true;
}
// 命令执行接口
bool PlateStack::ExcuteCmd(int cmd, const QByteArray& input, QByteArray& output)
{
	output = "错误的指令";
	return false;
}

bool PlateStack::RegisterSubscriberFunction(int type, Callback callback)
{
	if (type == 1) {
		m_callback.append(callback);
		return true;
	}

	return false;
}

void PlateStack::ResponseSystemState(int state)
{
	if (state == (int)SystemStateType::system_state_work) {
		m_time->start();
	} else {
		//m_time->stop();
	}
	m_sysState = state;
}

void PlateStack::OnTimeToExcute()
{
	// 检查托盘未知托盘是否存在
	MathPlateNum();
	if (m_sysState == (int)SystemStateType::system_state_work) {
		// 根据DI计算托盘架托盘数量
		CheckPlate();
		// 发送托盘架物料申请
		SendPlateStackApply();
	}
}

void PlateStack::CheckPlate()
{
	for (auto& iter : m_plates) {
		iter.second.plate = iter.first->GetPlateState();
		if (iter.second.plate) {
			iter.second.send = false;
		}
	}
	if (m_height.num <= 0) {
		// 托盘数量为0时，不需要产生托盘任务
		return;
	}

	for (auto& iter : m_plates) {
		if (iter.second.plate) {	// 托盘存在则判断下一个托盘
			continue;
		}
		// 当前位置托盘不存在，则生成当前托盘任务，结束for循环
		if (!iter.second.send) {	// 托盘不存在且之前未生成任务
			TaskDataJ task = {};
			task.taskId = iter.first->GetPlateId();
			task.grab = m_info.id;
			task.stackPlace = iter.first->GetPlateId();
			task.robNo = m_info.rob;
			task.taskType = 3;	// 平移货物
			task.skuList().clear();
			int ret = -1;
			for (auto& call : m_callback) {
				ret = call(task.toByteArray());
			}
			if (ret == 0) {
				log_trace("Send task {} successed", task.taskId());
				iter.second.send = true;
			} else {
				log_error("Send task {} failed", task.taskId());
			}
		}
		break;
	}
}
/*计算托盘数量*/
void PlateStack::MathPlateNum()
{
	int num = m_info.maxdi - m_info.mindi + 1;
	if (m_di.size() != num) {
		m_height.num = -1;
		m_height.times = 0;
		m_height.height = 0;
		return;
	}
	int flag = m_di.at(0);
	int height = 0;
	for (auto iter : m_di) {
		if (iter != flag && flag == 0) {
			m_height.num = -1;
			m_height.times = 0;
			m_height.height = 0;
			//SetErrmsg("光电DI异常");
			return;
		} else {
			flag = iter;
		}
		if (flag == 1) {
			height++;
		}
	}
	if (m_height.num != height) {
		log_trace("plate stack num from {} to {}", m_height.num, height);
		m_height.num = height;
		m_height.times = 1;
		m_height.height = (height - 1) * m_info.plateH;
	} else {
		m_height.times++;
	}
}

void PlateStack::SendPlateStackApply()
{
	// 连续3次识别到无托盘，需要向wcs发送托盘申请
	if (m_height.num == 0 && m_height.times > 3) {
		if (m_apply == PlateApplyState::apply_finish) {	//  申请成功后无需再申请
			return;
		}
		log_trace("plate num = 0, need send apply");
		m_apply = PlateApplyState::need_apply;
		PlateApply data = {};
		data.taskId = "0";
		data.robNo = m_info.rob;
		data.num = 10;
		data.placeNo = m_info.id;
		QByteArray ans;
		ApplyAns ansData;
		if (m_wcs->SendToWCS(PLATE_APPLY, data.toByteArray(), ans)) {
			log_trace("send apply successed");
			ansData.fromJson(ans);
			if (ansData.code() < 0) {
				SetWarningmsg("WCS拒绝了当前的托盘垛申请：" + ansData.msg());
				log_error("send to wcs apply msg failed, err = {}", ansData.msg());
				m_apply = PlateApplyState::apply_failed;
			} else {
				log_trace("send apply successed");
				m_apply = PlateApplyState::apply_finish;
			}
		} else {
			SetWarningmsg("向WCS申请托盘垛, 通知发送失败：" + ans);
			log_error("send to wcs apply msg failed, err = {}", ans);
			m_apply = PlateApplyState::apply_failed;
		}
	} else {
		m_apply = PlateApplyState::not_need_apply;
	}
}

#define TRIG ("1")
int PlateStack::RobotSetDIInfo(const QString& di)
{
	m_di.clear();
	if (m_info.mindi <= 0 || m_info.maxdi > 32) {
		SetErrmsg("托盘垛组件配置信息异常");
		return 0;
	}

	for (int i = m_info.mindi - 1; i < m_info.maxdi; i++) {
		if (di.at(i) == TRIG) {
			m_di.append(1);
		} else {
			m_di.append(0);
		}
	}

	return 0;
}

int PlateStack::WCSSendArrive(const QByteArray& data)
{
	ArriveInfo info = {};
	info.fromJson(data);
	if (info.type() != 4) {
		return -1;
	}
	if (info.stackPlace() == m_info.id) {
		log_trace("plate stack {} is arrived", info.stackPlace());
		return 0;
	}
	log_error("Not find  plate stack name is {}", info.stackPlace());
	return -1;
}